fn main(){
    let x = 1; // 可Copy
    let s = "abc"; // 字符串字面量被硬编码进程序，不可修改
    let str = String::from("hello"); // 不可Copy。不可修改。str是关键字但是用作变量名没报错

    let xx = x; // 栈上自动拷贝
    let ss = s; // 浅拷贝
    // let strx = str; // 将str`绑定`给strx，发生了`移动`。所有权转移，会使str不可再用
    let mut strx = str.clone(); // 深拷贝
    strx.push_str(" world"); // 修改操作，声明时需要加mul
    println!("{} {} {} {} {} {}", x, xx, s, ss, str, strx);

    let s1 = spawn_str(s);
    let mut s1 = change_str(s1); // 传参时发生了所有权转移，返回时又把所有权转移回来
    println!("{}", s1); // s1仍可用
    
    // 同一时刻，你只能拥有要么一个可变引用, 要么任意多个不可变引用
    // 可变引用与不可变引用不能在一个作用域中同时存在

    let s2 = &s1; // 创建s1的一个不可变引用。不会转移所有权。
    // let s3 = &mut s1; // 错误。已有别的引用了。
    println!("{}", *s2); // s2最后一次使用在这里，则编译器认为其作用域在这里结束
    let s3 = &mut s1; // 可以
    change_str_ori(s3); // s3的作用域到这里结束
    println!("{}", *s3);
    // rust的引用有点像指针，但是rust保证不存在悬垂引用，即任何解引用都是有效的

    // 可变引用才实现了Copy，不可变引用在赋值和传参时发生move
    let mut s4 = "hi".to_string();
    let cs = &s4;
    let mut cs1 = cs; // Copy
    cs1 = &s1; // mut表示cs1本身可以修改，但仍然不可以修改其引用的对象（不可变引用）
    // cs和cs1的作用域结束
    let ms = &mut s4; // s4本身可变，才能创建可变引用
    let ms1 = ms; // ms转移到ms1，ms失效
    // let ms2 = &mut s4; // 错误。同时存在两个可变引用
    let ms2 = &mut *ms1; // 这是可以的。ms2作用域从这里开始
    change_str_ori(ms2); // 在编译时视作 change_str_ori(&mut *ms2)
    println!("{}", *ms2); // ms2作用域从这里结束。如果ms2生效期间使用ms1会报错
    println!("{}", *ms1);

    // rust没有GC，也无需手动管理内存。*变量在离开作用域后，就会释放*（无论栈上的还是堆上的！）
    // 类似c的free，rust也有类似的drop函数。rust在变量离开作用域时会自动调用drop，这与C++的RAII概念有一致思想
}

fn spawn_str(s :&str) -> String {
    let s = String::from("aaa");
    s
    // &s // 错误。不能造成空悬引用
}

fn change_str(mut s :String) -> String {
    s.push_str("_change1");
    s // 返回 s 并移出给调用者
}

fn change_str_ori(s :&mut String) {
    s.push_str("_change2");
}
